# -*- coding: utf-8 -*-

import json
import os
import oss2
import requests

from com.maycur import config_loader
from conf.entity.module.oss_config import OssImageInfo


class OssOperation:

    bucket: oss2.Bucket
    backup_suffix = '__backup'

    def __init__(self):
        # 配置初始化
        oss_config = config_loader.get_oss_config()
        if oss_config:
            access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', oss_config.access_key_id)
            access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', oss_config.access_key_secret)
            bucket_name = os.getenv('OSS_TEST_BUCKET', oss_config.bucket_name)
            endpoint = os.getenv('OSS_TEST_ENDPOINT', oss_config.endpoint)

            # 确认上面的参数都填写正确了
            for param in (access_key_id, access_key_secret, bucket_name, endpoint):
                assert '<' not in param, '请设置参数：' + param

            # 创建Bucket对象，所有Object相关的接口都可以通过Bucket对象来进行
            self.bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name)

    def _upload(self, resource_key, data):
        self.bucket.put_object(resource_key, data)

    def upload_file(self, resource_key: str, file_path: str):
        if resource_key is None or resource_key == '' or file_path is None or file_path == '':
            return
        with open(file_path, 'rb') as f:
            self._upload(resource_key, f)

    def download(self, resource_key, download_file):
        # 下载到指定文件
        if download_file is not None and download_file != '':
            self.bucket.get_object_to_file(resource_key, download_file, (0, None))

    def get_resource_key_backup_name(self, resource_key: str, suffix='') -> str:
        """
        获取资源的备份名称，文件名(不带扩展名)以 "__backup" 结尾
        """
        parts = resource_key.split('.')
        if suffix == '':
            suffix = self.backup_suffix
        return f'{parts[0]}{suffix}.{parts[1]}'

    def backup_resource(self, resource_key: str, suffix=''):
        """备份OSS文件"""
        backup_resource_key = self.get_resource_key_backup_name(resource_key, suffix)
        temp_file_name = self.get_resource_key_backup_name(resource_key, '__temp')
        temp_file_name = temp_file_name.replace('/', '-')
        temp_file_path = ''
        try:
            # 从OSS服务起下载待备份文件到本地
            temp_file_path = os.path.join('/var/tmp', temp_file_name)
            if not os.path.exists(temp_file_path):
                # 创建文件
                temp_file = open(temp_file_path, 'w+')
                temp_file.close()
            self.download(resource_key, temp_file_path)

            # 用指定备份名称上传临时文件到OSS服务器
            self.upload_file(backup_resource_key, temp_file_path)
            print(f'resource: {backup_resource_key} backup finished')
        except Exception as e:
            print(f'failed to backup resource: {backup_resource_key}')
            raise e
        finally:
            # 删除临时文件
            if os.path.exists(temp_file_path):
                os.remove(temp_file_path)

    def get_signed_url_with_expiration(self, resource_key: str, process_style: str, expire_time: int):
        """
        获取带权限签名的URL
        expire_time: 单位毫秒
        """
        params = {'x-oss-process': process_style}
        return self.bucket.sign_url('GET', resource_key, expire_time, slash_safe=True, params=params)

    def get_signed_url(self, resource_key: str, process_style: str):
        # expire after 1 day
        expire_time = 1 * 24 * 3600 * 1000
        return self.get_signed_url_with_expiration(resource_key, process_style, expire_time)

    @staticmethod
    def is_image(resource_key: str) -> bool:
        if resource_key is None or resource_key == '' or '.' not in resource_key:
            return False
        candidates = ["jpeg", "bmp", "jpg", "png", "tiff", "gif", "pcx",
                      "tga", "exif", "fpx", "svg", "psd", "cdr", "pcd",
                      "dxf", "ufo", "eps", "ai", "raw", "wmf", "webp"]
        suffix = resource_key.split('.')[1].lower()
        return suffix in candidates

    def get_image_info(self, resource_key: str) -> OssImageInfo:
        # 获取Object的元信息
        object_meta = self.bucket.get_object_meta(resource_key)
        last_modified = str(object_meta.last_modified)

        # 获取图片信息
        image_info_url = self.get_signed_url(resource_key, 'image/info')
        image_info_res = requests.get(image_info_url)

        if image_info_res.status_code == 200:
            image_info_json = json.loads(image_info_res.text)
            oss_image_info = OssImageInfo()
            oss_image_info.last_modified = last_modified
            oss_image_info.image_height = int(image_info_json['ImageHeight']['value'])
            oss_image_info.image_width = int(image_info_json['ImageWidth']['value'])
            oss_image_info.file_size = int(image_info_json['FileSize']['value'])
            oss_image_info.format = image_info_json['Format']['value']
            return oss_image_info

    @staticmethod
    def print_image_info(image_info: OssImageInfo):
        if image_info is None:
            print('image info is none')
        else:
            print(f'format: {image_info.format}, width: {image_info.image_width}, height: {image_info.image_height}')

    def print_image_info_by_resource_key(self, resource_key: str):
        image_info = self.get_image_info(resource_key)
        self.print_image_info(image_info)

    @staticmethod
    def get_image_resize_command_within_4096(image_info: OssImageInfo):
        if image_info is None:
            return ''

        width = image_info.image_width
        height = image_info.image_height
        ratio = height / width
        if height > 4096 or width > 4096:
            if height > width:
                # height为长边，ratio > 1
                height = 4095
                width = int(height / ratio)
            else:
                # width为长边, ratio < 1
                width = 4095
                height = int(width * ratio)

        return f'resize,w_{width},h_{height}'
